﻿using System;
using System.Data;
using System.Configuration;

using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using TA.JSON;
using System.ComponentModel;
using System.Text;
using TA.DotNetUtils;
using TA.Turbo.Design;
using TA.Win.Utils.Design;
using System.Drawing.Design;



namespace TA.Turbo.Controls
{
	/// <summary>
	/// Base class for references to controls which can used to specify which controls need to be transferred as part of a form submission.
	/// </summary>
	public abstract class BaseControlReference : ControlTransferOptions, IJsonSerializable, IControlReference
	{
		#region PUBLIC
		#region INIT
		/// <summary>
		/// Ctor.
		/// </summary>
		public BaseControlReference()
		{
			Value = true;
			this.ControlId = "";
			this.SendAs = "";
		}
		#endregion
		#region PROPS
		/// <summary>
		/// Gets or sets the ID of the referenced control, relative to this control reference.
		/// </summary>
		[IDReferenceProperty]
		[TypeConverter(typeof(ControlIdConverter<TurboControlIdLister>))]
		[DefaultValue("")]
		[MergableProperty(false)]
		public string ControlId { get; set; }
		/// <summary>
		/// Gets the referenced control. 
		/// </summary>
		/// <remarks>
		/// This readonly property returns the control specified by ControlId.
		/// </remarks>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public Control Control
		{
			get
			{
				if (_control == null)
				{
					_control = this.FindControlGlobal(ControlId);
					if (_control == null)
						throw new InvalidOperationException(string.Format("Control ID '{0}' not found.", ControlId));
				}
				return _control;
			}
		}
		/// <summary>
		/// A string to use when sending the value and/or properties of this control to the server.
		/// </summary>
		[DefaultValue("")]
		[MergableProperty(false)]
		public string SendAs { get; set; }
		/// <summary>
		/// Returns all properties to be transferred as part of this control reference.
		/// </summary>
		/// <remarks>
		/// This prop. uses the referenced control's property definition list to figure out the final result (when PropertiesMode == AllButExcluded).
		/// </remarks>
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[Browsable(false)]
		public string[] AllPropertiesList
		{
			get
			{
				switch (this.PropertiesMode)
				{
					case InclusionMode.OnlyIncluded:
						return this.PropertiesList.ToArray();
					case InclusionMode.AllExceptExcluded:
						TControl tc = this.Control as TControl;
						if (tc == null)
							throw new InvalidOperationException("PropertiesMode can't be AllExceptExcluded for a control that is not a TControl.");
						return this.PropertiesMode.GetActive(this.PropertiesList, tc.ClientProperties.Keys);
				}
				throw new ArgumentException();
			}
		}
		/// <summary>
		/// List of properties to be included or excluded, depending on the PropertiesMode, from the request. (connected to Properties)
		/// </summary>
		[Editor(typeof(StringCollectionEditor<PropertiesOptionsProvider>), typeof(UITypeEditor))]
		public override List<string> PropertiesList
		{
			get
			{
				return base.PropertiesList;
			}
		}
		#endregion
		#region METHODS
		/// <summary>
		/// Merges the specified control reference with this one.
		/// </summary>
		/// <param name="cr">The control reference to merge into this one.</param>
		public void Ensure(BaseControlReference cr)
		{
			this.Value |= cr.Value;

			TControl bc = this.Control as TControl;
			foreach (string prName in bc.ClientProperties.Keys)
			{
				if (MultiPartValue.IsIncluded(cr.PropertiesMode, cr.PropertiesList, prName)
					&& !MultiPartValue.IsIncluded(this.PropertiesMode, this.PropertiesList, prName))
				{
					if (this.PropertiesMode == InclusionMode.OnlyIncluded)
						this.PropertiesList.Add(prName);
					else
						this.PropertiesList.Remove(prName);
				}
			}
		}
		/// <summary>
		/// Returns the string representation of this instance.
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			if (this.Control != null)
			{
				StringBuilder sb = new StringBuilder();
				sb.AppendFormat("Ref. '{0}': ", this.Control.UniqueID);
				if (this.Value)
					sb.Append("Value; ");
				if (this.PropertiesMode == InclusionMode.AllExceptExcluded)
					sb.Append("all but ");
				foreach (string prName in this.PropertiesList)
				{
					sb.Append(prName);
					sb.Append(", ");
				}
				return sb.ToString();
			}
			return base.ToString();
		}
		#endregion
		#endregion
		#region INTERNAL
		#region VARS
		Control _control;
		#endregion
		#region IJsonSerializable Members
		/// <summary>
		/// IsDirty.
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public bool IsDirty
		{
			get { return true; }
		}
		/// <summary>
		/// Serialize.
		/// </summary>
		/// <param name="jw"></param>
		public void Serialize(JsonWriter jw)
		{
			this.SerializeObject(jw);
		}
		/// <summary>
		/// SerializeContents.
		/// </summary>
		/// <param name="jw"></param>
		public void SerializeContents(JsonWriter jw)
		{
			jw.PropertyName("I");
			jw.Value(this.Control.ClientID);

			if (!this.Value)
			{
				jw.PropertyName("V");
				jw.Value(0);
			}

			if (this.AllPropertiesList.Length > 0)
			{
				jw.PropertyName("P");

				jw.StartArray();
				foreach (string pName in this.AllPropertiesList)
					jw.Value(TPage.PrepareScript(pName));
				jw.EndArray();
			}

			if (!string.IsNullOrEmpty(this.SendAs))
			{
				jw.PropertyName("S");
				jw.Value(this.SendAs);
			}
		}

		#endregion
		#endregion
	}
}